package com.learning.security.service;

import com.learning.security.dal.dataobject.AdminOAuth2AccessTokenDO;
import com.learning.security.dal.dataobject.AdminOAuth2RefreshTokenDO;
import com.learning.security.dal.dataobject.AdminUserDO;
import com.learning.security.dal.mysql.AdminOauth2AccessTokenMapper;
import com.learning.security.dal.mysql.AdminOauth2RefreshTokenMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Service
public class AdminOAuth2TokenServiceImpl implements AdminOAuth2TokenService {
    @Lazy
    @Autowired
    private AdminUserService adminUserService;

    @Autowired
    private AdminOauth2RefreshTokenMapper adminOauth2RefreshTokenMapper;

    @Autowired
    private AdminOauth2AccessTokenMapper adminOauth2AccessTokenMapper;

    @Override
    public AdminOAuth2AccessTokenDO createAccessToken(Long userId, String username) {
        AdminOAuth2RefreshTokenDO refreshTokenDO = createOAuth2RefreshToken(userId, username);

        return createOAuth2AccessToken(refreshTokenDO);
    }

    @Override
    public AdminOAuth2AccessTokenDO checkAccessToken(String accessToken) {
        AdminOAuth2AccessTokenDO accessTokenDO = getAccessToken(accessToken);
        if (Objects.isNull(accessTokenDO)) {
            throw new RuntimeException("access token is not exist");
        }

        if (LocalDateTime.now().isAfter(accessTokenDO.getExpiresTime())) {
            throw new RuntimeException("access token is expired");
        }
        return accessTokenDO;
    }

    private AdminOAuth2AccessTokenDO getAccessToken(String accessToken) {
        return adminOauth2AccessTokenMapper.selectByAccessToken(accessToken);
    }

    private AdminOAuth2AccessTokenDO createOAuth2AccessToken(AdminOAuth2RefreshTokenDO refreshTokenDO) {
        AdminOAuth2AccessTokenDO accessTokenDO = new AdminOAuth2AccessTokenDO().setAccessToken(generateAccessToken())
                .setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType())
                .setUserInfo(buildUserInfo(refreshTokenDO.getUserId()))
                .setClientId(refreshTokenDO.getClientId()).setScopes(refreshTokenDO.getScopes())
                .setRefreshToken(refreshTokenDO.getRefreshToken())
                .setExpiresTime(LocalDateTime.now().plusSeconds(120L));
        accessTokenDO.setTenantId(1L);
        adminOauth2AccessTokenMapper.insert(accessTokenDO);
        return accessTokenDO;
    }

    private Map<String, String> buildUserInfo(Long userId) {
        AdminUserDO user = adminUserService.getUser(userId);
        Map<String, String> userInfo = new HashMap<>();
        userInfo.put("nickname", user.getNickname());
        return userInfo;
    }

    private AdminOAuth2RefreshTokenDO createOAuth2RefreshToken(Long userId, String username) {
        AdminOAuth2RefreshTokenDO refreshTokenDO = new AdminOAuth2RefreshTokenDO().setRefreshToken(generateRefreshToken())
                .setUserId(userId)
                .setUserType(1)
                .setClientId("1")
                .setScopes(Collections.EMPTY_LIST)
                .setExpiresTime(LocalDateTime.now().plusSeconds(120L));
        adminOauth2RefreshTokenMapper.insert(refreshTokenDO);
        return refreshTokenDO;
    }

    private static String generateRefreshToken() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    private static String generateAccessToken() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}
